package tasks

import (
	"database/sql"
	"fmt"
	"time"

	"torler.com/qingyue/apps/spider/internal/core"
	"torler.com/qingyue/apps/spider/internal/core/task"
	"torler.com/qingyue/apps/spider/internal/site"
	"torler.com/qingyue/common/model"
	"torler.com/qingyue/common/types"
)

const (
	RUNNER_LAST_UPDATE = types.RunnerName("spider_lastest_cbook")
	TASK_LAST_UPDATE   = types.TaskName("渠道最近更新爬虫")
)

type LastUpdateSpider struct {
}

// 任务执行者预加载
func (it *LastUpdateSpider) Preload(t *task.Task) error {
	return nil
}

func NewLastUpdateSpider() *LastUpdateSpider {
	return &LastUpdateSpider{}
}

// 任务执行者的唯一名称标识用于反序列化
func (it *LastUpdateSpider) Name() types.RunnerName {
	return RUNNER_LAST_UPDATE
}

// 任务执行者
func (it *LastUpdateSpider) Run(tsk *task.Task) error {

	siteId := task.GetParam[types.SourceId](tsk, "site_id")

	// 检查siteId是否有效
	if siteId.IsZero() {
		return fmt.Errorf("无效的站点ID: %v", siteId)
	}

	parse := site.GetParserBySiteId(siteId)
	if parse == nil {
		return fmt.Errorf("未找到站点 %d 的解析器", siteId)
	}

	url := parse.GetLastUpdateUrl()
	if url == "" {
		return fmt.Errorf("站点 %d 的更新URL为空", siteId)
	}

	selector := parse.GetLastUpdateSelector()
	logger := tsk.Logger().With("url", url, "selector", selector)

	// 创建请求克隆以避免并发问题
	page, err := browser.NewPage()
	if err != nil {
		return fmt.Errorf("创建浏览器页面失败: %w", err)
	}
	defer page.Close()

	page.Goto(url)

	cbooks, err := parse.ParseLastUpdate(page)
	if err != nil {
		logger.Error("解析更新内容失败", "error", err)
		return err
	}
	count, err := it.saveLastupdateBooks(tsk.GetCtx(), siteId, tsk, cbooks)
	if err == nil {
		total := len(cbooks)
		tsk.SetResult("抓取到小说数量", total).
			SetResult("有效更新数量", count)
		logger.Info("最近更新", "总数", total, "有效", count)

	} else {
		logger.Error("保存更新内容失败", "error", err)
		return err
	}
	logger.Info("最近更新抓取完成")
	return nil
}

// saveLastupdateBooks 保存最近更新的小说
//
// 查询最后更新50本小说，并去除掉已经存在的，并在日志中记录有效的数量
func (it *LastUpdateSpider) saveLastupdateBooks(ctx *core.AppContext, siteId types.SourceId, tsk *task.Task, books []*model.LastestCBook) (count int, err error) {
	var lastUpdates []*model.LastestCBook
	tx := ctx.DB.Find(&lastUpdates, "site_id = ?", siteId).Limit(30).Order("update_time desc")
	if tx.Error != nil {
		return 0, tx.Error
	}
	var updates []*model.LastestCBook
	for _, book := range books {
		has := false
		for _, lastUpdate := range lastUpdates {
			//若id一致，则有记录
			if lastUpdate.OId.String() == book.OId.String() {
				// 若章节一致，则无更新,处理下一本小说
				if lastUpdate.LastChapterId != book.LastChapterId {

					updates = append(updates, lastUpdate)

				}
				has = true
				break
			}
		}
		// 若无记录，则添加
		if !has {
			updates = append(updates, book)
		}

	}
	if len(updates) == 0 {
		return 0, nil
	}
	for _, update := range updates {
		//重置为未计划状态，让爬虫按计划重新抓取
		update.Sched = false
		update.UpdateTime = sql.NullTime{
			Time:  time.Now(),
			Valid: true,
		}
	}

	tx = ctx.DB.Save(updates)
	if tx.Error != nil {
		return 0, tx.Error
	}

	return int(tx.RowsAffected), nil

}
